package org.dxy.domain.handler.workorder;

import com.google.common.eventbus.EventBus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.domain.port.IEventRepository;
import org.dxy.domain.port.IdGenerator;
import org.dxy.domain.handler.CommandHandler;
import org.dxy.domain.port.repository.IWorkOrderRepository;
import org.dxy.domain.command.workorder.CreateWorkOrderCommand;
import org.dxy.domain.event.DomainEvent;
import org.dxy.domain.model.aggregate.factory.WorkOrderFactory;
import org.dxy.domain.model.aggregate.WorkOrder;
import org.dxy.domain.service.WorkOrderCodeGenerator;
import org.dxy.types.common.CommandResult;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.List;

/**
 * 创建工单命令处理器
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CreateWorkOrderCommandHandler implements CommandHandler<CreateWorkOrderCommand, Long> {

    private final IWorkOrderRepository workOrderRepository;
    private final WorkOrderFactory workOrderFactory;
    private final WorkOrderCodeGenerator codeGenerator;
    private final EventBus eventBus;
    private final IdGenerator idGenerator;
    private final IEventRepository eventRepository;
    
    @Transactional
    @Override
    public CommandResult<Long> handle(CreateWorkOrderCommand command) {
        // 1. 验证命令参数
        command.validate();
        
        // 2. 验证工单编码格式
        if (!codeGenerator.validateCodeFormat(command.workOrderCode())) {
            throw new IllegalArgumentException("工单编码格式错误，必须符合格式 WO-YYYYMMDD-NNN");
        }
        
        // 3. 校验工单编码唯一性
        if (workOrderRepository.existsByCode(command.workOrderCode())) {
            throw new IllegalArgumentException("工单编码已存在: " + command.workOrderCode());
        }

        // 4. 生成工单ID
        Long workOrderId = idGenerator.generate();
        
        // 5. 使用工厂创建聚合根（工厂内部会进行业务规则验证）
        WorkOrder workOrder = workOrderFactory.create(workOrderId, command);
        
        // 6. 保存聚合根
        workOrderRepository.save(workOrder);

        List<DomainEvent> events = workOrder.getDomainEvents();
        
        // 7. 保存事件到事件存储，获取固定的事件ID列表
        List<Long> eventIds = eventRepository.saveEvents(events);
        
        // 8. 创建事件副本用于发布
        List<DomainEvent> eventsCopy = new ArrayList<>(events);
        
        // 9. 注册事务提交后的事件发布回调
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                // 使用事务提交前保存的事件副本
                eventsCopy.forEach(eventBus::post);

                // 当事件发布成功后，会把这个字段标记为 true；（如果系统崩溃或重启，可以扫描未发布的事件（published = false）重新发布，保证"最终一致性"。）
                eventRepository.markEventsPublished(eventIds);

                // 10. 清理事件
                workOrder.clearDomainEvents();
            }
        });

        log.info("工单创建成功 - 工单编码: {}, 状态: 准备完成", command.workOrderCode());
        return CommandResult.success(workOrderId, "工单 " + command.workOrderCode() + " 创建成功，状态：准备完成");
    }
}